package com.cy.store.service.impl;

import com.cy.store.entity.User;
import com.cy.store.mapper.UserMapper;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.UUID;

/**
 * @author ZhangSir
 */
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    /**
     *
     */
    @Override
    public void reg(User user) {
        // 先获取注册的用户名，由字符串接受
        String username = user.getUsername();
        // 根据字符串查询用户名是否已经存在，并将查询结果由user类型的对象接受
        User result = userMapper.findByUsername(username);
        // 判断查询结果是否为空，如果为空表明该用户名未被注册，如果不为空表示该用户名已被占用注册
        if (result != null){
            // 抛出异常
            throw new UsernameDuplicatedException("用户名被占用");
        }
        /** 先对密码进行加密，md5算法的方式，串+密码+串，即盐值+密码+盐值，盐值是一个随机的字符串 */
        // 1.获取注册用户的密码
        String password = user.getPassword();
        // 2.随机生成一个字符串并交由salt盐值来接收
        String salt = UUID.randomUUID().toString();
        // 3. 调用md5加密算法对用户的密码进行加密
        String md5Password = getMD5Password(salt,password);
        // 4.将加密后的密码重新set到user数据中
        user.setPassword(md5Password);
        // 5.将盐值也要set到user数据中，因为每个用户注册生成的盐值都不一样，必须将盐值保存下来，用户下次登陆时，
        //   将输入的密码和自己的盐值重新拼接，与数据库中的加密后的密码进行比较，相同则登陆成功，不同则为密码错误登陆失败
        user.setSalt(salt);

        // 执行注册业务功能,在插入之前要不全一部分信息,补全四个日志信息
        user.setIsDelete(0);
        user.setCreatedUser(user.getUsername());
        Date date = new Date();
        user.setCreatedTime(date);
        user.setModifiedUser(user.getUsername());
        user.setModifiedTime(date);
        Integer row = userMapper.insert(user);
        // 5.对直径结果进行判断，不一定执行插入方法就一定成功，有可能在过程中发生不可预知的错误
        if (row != 1){
            throw new InsertException("服务器发生故障，注册失败");
        }
    }

    @Override
    public User login(String username, String password) {
        // 先通过传入过来的username查找该用户
        User result = userMapper.findByUsername(username);
        // 再判断该用户是否存在，或之前存在现在已经注销，判断依据为result的username是否为空或isDelete是否为1
        // 如果满足其中任意一个条件，抛出该用户未找到的异常
        if (result == null || result.getUsername() == null || result.getIsDelete() == 1){
            throw new UserNotFoundException("该用户未找到");
        }
        // 如果程序走到这里，说明存在该用户，然后再判断该用户的密码是否都输入正确，则需要先获取该用户对应的盐值，
        // 通过md5加密算法对传入进来的密码进行加密，再与数据库中的密码进行比较，相同则密码正确，不同则为密码错误
        String salt = result.getSalt();
        String oldPassword = result.getPassword();
        String md5Password = getMD5Password(salt,password);
        if (!md5Password.equals(oldPassword)){
            throw new PasswordNotMatchException("密码输入错误");
        }
        // 这里的话我们重新new一个user对象，只保存用户id，用户名，用户头像三个属性，
        // 因为我们查询到的result 对象里面数据较多，有一部分用不到，所以这里进行一个数据的压缩，对系统性能进行调优
        User user = new User();
        user.setUid(result.getUid());
        user.setUsername(result.getUsername());
        user.setAvatar(result.getAvatar());
        return user;
    }

    @Override
    public User findByUid(Integer id) {
        User result = userMapper.findByUid(id);
        if (result == null || result.getIsDelete() == 1){
            throw new UserNotFoundException("该用户不存在");
        }
        User user = new User();
        user.setUsername(result.getUsername());
        user.setPhone(result.getPhone());
        user.setEmail(result.getEmail());
        user.setGender(result.getGender());
        return user;
    }

    @Override
    public void changePassword(Integer id, String username, String oldPassword, String newPassword) {
        User result = userMapper.findByUid(id);
        // 进行判空操作，如果result为空，则无法修改密码，直接抛出异常
        if (result == null || result.getIsDelete() == 1){
            throw new UserNotFoundException("未找到该用户");
        }
        // 进行到这一步，说明该用户存在，所以接下来判断该用户输入的原密码是否正确
        // 1.获取用户盐值
        String salt = result.getSalt();
        // 2，调用md5加密算法还原用户密码
        String oldMd5Password = getMD5Password(salt,oldPassword);
        // 3.将还原后的原密码与数据库密码进行匹配，相等则原密码输入正确，不相等则输入错误
        if (!oldMd5Password.equals(result.getPassword())){
             throw new PasswordNotMatchException("密码输入错误");
        }
        // 开始正式修改密码。先接收用户修改后的密码,进行md5加密算法
        String newMd5Password = getMD5Password(salt,newPassword);
        Integer rows = userMapper.updatePasswordByUid(id,newMd5Password,username,new Date());
        if (rows != 1){
            throw new UpdateException("修改密码时发生未知异常");
        }
    }

    @Override
    public void changeInfo(Integer id, String username, User user) {
        User result = userMapper.findByUid(id);
        if (result == null || result.getIsDelete() == 1){
            throw new UserNotFoundException("该用户不存在");
        }
        user.setUid(id);
        user.setModifiedUser(username);
        user.setModifiedTime(new Date());
        Integer rows = userMapper.updateInfoByUid(user);
        if (rows != 1){
            throw new UpdateException("更新时发生错误");
        }
    }

    // 修改用户头像
    @Override
    public void changeAvatar(Integer uid, String avatar, String username) {
        User result = userMapper.findByUid(uid);
        if (result == null || result.getIsDelete() == 1){
            throw new UserNotFoundException("该用户不存在");
        }
        Integer row = userMapper.updateAvatarByUid(uid,avatar,username,new Date());
        if (row != 1){
            throw new UpdateException("修改用户头像时发生未知异常");
        }
    }

    @Override
    public User findByUsername(String username) {
        return userMapper.findByUsername(username);
    }

    // 定义一个md5算法加密方法
    public String getMD5Password(String salt,String password){
        for (int i = 0;i < 3;i++){
            password = DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();
        }
        return password;
    }
}
